package com.caishi.lkx.common.role;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.caishi.lkx.common.CommonResultCode;
import com.zzw.common.IUserContext;
import com.zzw.common.ResultCode;
import com.caishi.lkx.common.AclResultCode;
import com.caishi.lkx.common.context.TokenData;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author by keray
 * date:2021/4/1 5:01 下午
 */
@Configuration("roleAuth")
public class RoleAuth implements RoleAuthService {

    private final Map<String, Set<String>> roleCache = new ConcurrentHashMap<>(256);

    @Resource
    private IUserContext<TokenData> userContext;

    @Resource
    private RoleAuthConfig roleAuthConfig;

    private long systemStartTime;

    @PostConstruct
    void init() {
        systemStartTime = System.currentTimeMillis();
    }


    public ResultCode apply(String methodSign, Roles roles, HttpServletRequest request) {
        Set<String> role = new LinkedHashSet<>();
        String path = request.getRequestURI();
        if (systemStartTime < roleAuthConfig.getConfLastTime()) {
            systemStartTime = roleAuthConfig.getConfLastTime();
            roleCache.clear();
        }
        if (roleCache.containsKey(methodSign)) {
            role = roleCache.get(methodSign);
        } else {
            String originConf = pathContainsConf(path);
            if (StrUtil.isNotBlank(originConf)) {
                role.addAll(Arrays.stream(originConf.split(",")).collect(Collectors.toList()));
            }
            if (roles != null) {
                role.addAll(Arrays.stream(roles.value()).map(Enum::name).collect(Collectors.toSet()));
                role.addAll(Arrays.stream(roles.roles()).collect(Collectors.toSet()));
            } else if(CollUtil.isEmpty(role)){
                role.add(Role.onlyLogin.name());
            }
            roleCache.put(methodSign, role);
        }
        if (role.contains(Role.none.name())) {
            return CommonResultCode.ok;
        }
        if (!role.contains(Role.none.name()) && !userContext.loginStatus()) {
            return AclResultCode.notLogin;
        } else if (role.contains(Role.onlyLogin.name()) && userContext.loginStatus()) {
            return CommonResultCode.ok;
        } else {
            // 加载用户接口权限级别，
            List<String> userRoles = userContext.currentTokenData().getUserRole();
            if (CollUtil.isNotEmpty(userRoles)) {
                for (String roleStr : userRoles) {
                    if (roleStr.equals(Role.maxAdmin.name()) || role.contains(roleStr)) {
                        return CommonResultCode.ok;
                    }
                }
            }
        }
        return AclResultCode.noPower;
    }

    private String pathContainsConf(String path) {
        Map<String, String> conf = roleAuthConfig.getConf();
        for (Map.Entry<String, String> entry : roleAuthConfig.swagger.entrySet()) {
            if (path.matches(entry.getKey())) {
                return entry.getValue();
            }
        }
        if (conf != null) {
            for (Map.Entry<String, String> entry : roleAuthConfig.getConf().entrySet()) {
                if (path.matches(entry.getKey())) {
                    return entry.getValue();
                }
            }
        }
        return null;
    }
}
